<template>
  <div class="todoList">
    <div class="headerBar">任务计划列表</div>
    <div class="bodyContent">
      <div class="opt">
        <el-form
          :inline="true"
          :model="formInline"
          class="evt-form-inline"
          :rules="formInlineRules"
          ref="formInlineForm"
          @submit.prevent
        >
          <el-form-item label="添加任务" prop="todoDes" class="addTisks">
            <el-input
              v-model="formInline.text"
              placeholder="请输入待办事务，回车即可添加"
              style="width:400px;margin-right:20px;"
              maxlength="200"
              @keyup.enter="onSubmit()"
            ></el-input>
            <el-button type="danger" @click="onSubmit()" class="task-button">添加</el-button>
          </el-form-item>
        </el-form>
      </div>
      <el-divider content-position="left">
        任务列表：使用浏览器本地缓存，刷新不会丢失，同时支持任务列表拖拽与
        <span class="file-opt" @click="exprotFile()">[导出]</span>
        <span class="file-opt">
          [导入]
          <input type="file" ref="file" class="input" @change="importFile($event)" />
        </span>
      </el-divider>
      <div class="dayTitle">今日任务：</div>
      <div class="dayList">
        <draggable
          :list="allTodoList.dayTodoList"
          group="people"
          itemKey="todoDes"
          class="list-group"
        >
          <template #item="{ element, index }">
            <div class="tisk">
              <input class="checkbox" type="checkbox" v-model="element.status" />
              <span :class="element.status ? 'text textDel' : 'text'">{{ element.todoDes }}</span>
              <el-button
                type="text"
                size="mini"
                class="taskDel"
                @click="deleteLine(element, index, 'todoList')"
              >删除</el-button>
            </div>
          </template>
        </draggable>
      </div>
      <div class="dayTitle">本周任务：</div>
      <div class="dayList">
        <draggable
          :list="allTodoList.weekTodoList"
          group="people"
          itemKey="todoDes"
          class="list-group"
        >
          <template #item="{ element, index }">
            <div class="tisk">
              <input class="checkbox" type="checkbox" v-model="element.status" />
              <span :class="element.status ? 'text textDel' : 'text'">{{ element.todoDes }}</span>
              <el-button
                type="text"
                size="mini"
                class="taskDel"
                @click="deleteLine(element, index, 'weekTodoList')"
              >删除</el-button>
            </div>
          </template>
        </draggable>
      </div>
      <div class="dayTitle">任务记录：</div>
      <div class="dayList">
        <draggable
          :list="allTodoList.taskTodoList"
          group="people"
          itemKey="todoDes"
          class="list-group"
        >
          <template #item="{ element, index }">
            <div class="tisk">
              <input class="checkbox" type="checkbox" v-model="element.status" />
              <span :class="element.status ? 'text textDel' : 'text'">{{ element.todoDes }}</span>
              <el-button
                type="text"
                size="mini"
                class="taskDel"
                @click="deleteLine(element, index, 'taskTodoList')"
              >删除</el-button>
            </div>
          </template>
        </draggable>
      </div>
    </div>
  </div>
</template>
<script lang="ts">
import {
  ComponentInternalInstance,
  getCurrentInstance,
  ref,
  reactive,
  defineComponent,
  onMounted,
  watch,
} from "vue";
import { LocalStorage } from "storage-manager-js";
import draggable from "vuedraggable";
import FileSaver from "file-saver";
import { ElMessage, ElMessageBox } from "element-plus";

//定义element form对象类型
import type { ElForm } from 'element-plus'
type ElFormInstance = InstanceType<typeof ElForm>

//定义任务类型
interface TAST {
  todoDes: string;
  status: boolean;
}

//定义整体类型
interface TODOLIST {
  dayTodoList: Array<TAST>;
  taskTodoList: Array<TAST>;
  weekTodoList: Array<TAST>;
}

//定义表单类型
interface FORM {
  text: string;
}

/**
 * 添加操作模块
 * @function useAddTodo
 */
function useAddTodo(allTodoList:TODOLIST) {
  //let dayTodoList = allTodoList.dayTodoList来使用allTodoList会丢失响应式，最后需要allTodoList.dayTodoList = dayTodoList
  //绑定ref的Dom
  const formInlineForm = ref<ElFormInstance | null>(null);
  //响应式变量
  const formInline = reactive<FORM>({text:''});

  const resetForm = () => {
    (formInlineForm.value as ElFormInstance).resetFields();
  };

  //返回提交函数
  const onSubmit = () => {
    console.log("onSubmit",formInline);
    (formInlineForm.value as any).validate((valid: boolean) => {
      if (valid) {
        let task:TAST = {
          todoDes: formInline.text,
          status: false
        };
        allTodoList.dayTodoList.unshift(task);
        formInline.text = "";
        resetForm();
      } else {
        console.log("error submit!!");
        return false;
      }
    });
  };

  return {
    formInlineForm,
    formInline,
    onSubmit,
    resetForm,
  };
}

/**
 * 数据导入出
 * @function useAddTodo
 */
function useDateImportExport(allTodoList:TODOLIST) {
  const currentInstance = getCurrentInstance() as ComponentInternalInstance;
  const exprotFile = () => {
    let data = JSON.stringify(allTodoList);
    let blob = new Blob([data], {
      type: "text/plain;charset=utf-8",
    });
    let date = new Date();
    let time =
      date.getFullYear() + "-" + date.getMonth() + 1 + "-" + date.getDay();
    FileSaver.saveAs(blob, "todoList." + time + ".txt");
  };

  const importFile = (evt: any) => {
    ElMessageBox.confirm("导入将会覆盖现在的任务列表，确定?", "Warning", {
      confirmButtonText: "确定",
      cancelButtonText: "取消",
      confirmButtonClass: "task-button",
      type: "warning",
    })
      .then(() => {
        let selectedFile = evt.target.files[0];
        let reader = new FileReader();
        reader.readAsText(selectedFile);
        reader.onload = function () {
          let result: string = this.result as string; //加类型断言告诉编译器这个值是String
          if (result) {
            try {
              let obj = JSON.parse(result);
              console.log(allTodoList);
              allTodoList.weekTodoList = obj.weekTodoList;
              allTodoList.taskTodoList = obj.taskTodoList;
              allTodoList.dayTodoList = obj.dayTodoList;
            } catch {
              ElMessage.error("文件导入不正确，请检查");
            }
          }
        };
        (currentInstance as any).ctx.$refs["file"].value = null;
      })
      .catch(() => {
        (currentInstance as any).ctx.$refs["file"].value = null;
      });
  };

  return {
    importFile,
    exprotFile,
  };
}

/**
 * 删除数据
 * @function useAddTodo
 */
function useTaskList(allTodoList:TODOLIST) {
  const deleteLine = (row: TAST, index: number , type: string) => {
    let arr:Array<TAST>  = allTodoList.dayTodoList;
    if (type == "weekTodoList") {
      arr = allTodoList.weekTodoList;
    }
    if (type == "taskTodoList") {
      arr = allTodoList.taskTodoList;
    }
    arr.forEach((item:TAST, index:number ) => {
      if (item.todoDes === row.todoDes) {
        arr.splice(index, 1);
      }
    });
  };
  return {
    deleteLine,
  };
}

export default defineComponent({
  name: "todoList",
  components: {
    draggable,
  },

  setup: (props, context) => {
    console.log("setup", props, context);

    //定义响应式
    let obj: any = LocalStorage.get("allTodoList")
      ? LocalStorage.get("allTodoList")
      : {
        dayTodoList: [],
        weekTodoList: [],
        taskTodoList: [],
      };
    let allTodoList = reactive(obj);

    /*---------------------------添加待办业务-------------------------*/
    const { formInlineForm, formInline, onSubmit, resetForm } =
      useAddTodo(allTodoList);

    /*---------------------------添加导入导出业务----------------------*/
    const { exprotFile, importFile } = useDateImportExport(allTodoList);

    /*---------------------------任务列表事务-------------------------*/
    const { deleteLine } = useTaskList(allTodoList);

    /*---------------------------监听事务-------------------------*/
    //监听todoList
    watch(allTodoList, () => {
      console.log("allTodoList改变", allTodoList);
      LocalStorage.set("allTodoList", allTodoList);
    });

    /*---------------------------返回响应式数据-------------------------*/
    return {
      formInline,
      onSubmit,
      resetForm,
      formInlineForm,
      formInlineRules: {
        text: [
          { required: true, message: "请输入待办任务", trigger: "blur" },
          {
            min: 1,
            max: 200,
            message: "长度在 1 到 200 个字符",
            trigger: "blur",
          },
        ],
      },
      allTodoList,
      deleteLine,
      exprotFile,
      importFile,
    };
  },
});
</script>

<style>
body {
  background: #fcfcfc;
}
.todoList .el-form-item__label {
  font-size: 20px;
  font-weight: 600;
}

.todoList .el-input__inner:focus {
  border-color: #c96318;
}

.todoList .list-group {
  cursor: move;
}

.todoList .taskDel {
  cursor: pointer;
}
.el-message-box .task-button,
.todoList .task-button {
  background: #e42b2b;
  border-color: #d45858;
}

.el-button:hover {
  color: rgb(207, 204, 204);
  border-color: #ccc;
}
</style>

<style scoped lang="scss">
.todoList {
  width: 100%;
  margin: 0 auto;

  .headerBar {
    height: 50px;
    background: #d40000;
    color: #fff;
    line-height: 50px;
    font-size: 22px;
    margin-bottom: 50px;
    font-weight: 600;
  }

  .bodyContent {
    width: 650px;
    margin: auto;
  }

  .dayTitle {
    margin-top: 20px;
    font-size: 20px;
    font-weight: 600;
    text-align: left;
    margin-bottom: 20px;
  }

  .tisk {
    height: 50px;
    line-height: 50px;
    width: 100%;
    background: #f1f1f1;
    margin: 5px 0;
    text-align: left;
    font-size: 20px;
    padding: 0 10px;
  }

  .checkbox:checked {
    background: #d40000;
  }
  .checkbox {
    vertical-align: middle;
    width: 30px;
    height: 30px;
    background-color: #ffffff;
    border: solid 1px #dddddd;
    -webkit-border-radius: 50%;
    border-radius: 50%;
    font-size: 0.8rem;
    margin: 0 10px;
    padding: 0;
    position: relative;
    display: inline-block;
    cursor: default;
    -webkit-appearance: none;
    -webkit-user-select: none;
    user-select: none;
    -webkit-transition: background-color ease 0.1s;
    transition: background-color ease 0.1s;
  }
  .checkbox:checked::after {
    content: "";
    top: 8px;
    left: 8px;
    position: absolute;
    background: transparent;
    border: #fff solid 2px;
    border-top: none;
    border-right: none;
    height: 6px;
    width: 10px;
    -moz-transform: rotate(-45deg);
    -ms-transform: rotate(-45deg);
    -webkit-transform: rotate(-45deg);
    transform: rotate(-45deg);
  }
  .text {
  }

  .textDel {
    text-decoration: line-through;
    color: #dddddd;
  }
  .taskDel {
    float: right;
    margin-top: 12px;
    cursor: pointer;
    color: #d40000;
  }
  .file-opt {
    color: #d40000;
    margin: 0px 2px;
    cursor: pointer;
    display: inline-block;
    position: relative;
  }
  .input {
    width: 35px;
    height: 25px;
    opacity: 0;
    display: block;
    position: absolute;
    left: 0;
    top: 0px;
    cursor: pointer;
    font-size: 0;
  }
}
</style>
